package models

//工作流活动
import (
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strings"
	"time"

	"gitee.com/lzqysoft/ims/libs"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

//Action 活动表
type Action struct {
	Id                 string                `orm:"column(id);pk"`
	Name               string                `orm:"column(name);null"`
	Remark             string                `orm:"column(remark);null"`
	Status             int                   `orm:"column(status)"`
	Isdelete           int                   `orm:"column(isdelete)"`
	Ctime              time.Time             `orm:"column(ctime);type(timestamp with time zone)"`
	Creater            string                `orm:"column(creater)"`
	Utime              time.Time             `orm:"column(utime);type(timestamp with time zone)"`
	Updater            string                `orm:"column(updater)"`
	Key                string                `orm:"column(key)"`
	Transition         []*Transition         `orm:"reverse(many)"`
	TransitionInstance []*TransitionInstance `orm:"reverse(many)"`
}

// TableName TableName
func (t *Action) TableName() string {
	return "fsm_action"
}

func init() {
	orm.RegisterModel(new(Action))
}

// AddAction insert a new Action into database and returns
// last inserted Id on success.
func AddAction(m *Action) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetActionById retrieves Action by Id. Returns error if
// Id doesn't exist
func GetActionById(id string) (v *Action, err error) {
	o := orm.NewOrm()
	v = &Action{Id: id}
	if err = o.Read(v); err == nil {
		return v, nil
	}
	return nil, err
}

func GetActionByName(name string) (*Action, error) {
	o := orm.NewOrm()
	var ev Action
	qs := o.QueryTable(new(Action))
	qs = qs.Filter("Name", name).Filter("Status", 1).Filter("Isdelete", 0)
	err := qs.One(&ev)
	return &ev, err
}

// GetAllAction retrieves all Action matches certain condition. Returns empty list if
// no records exist
func GetAllAction(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Action))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		if strings.Contains(k, "isnull") {
			qs = qs.Filter(k, (v == "true" || v == "1"))
		} else {
			qs = qs.Filter(k, v)
		}
	}
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []Action
	qs = qs.OrderBy(sortFields...).Filter("Isdelete", 0).Filter("Status", 1)
	if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateAction  updates Action   and returns error if
// the record to be updated doesn't exist
func UpdateAction(m *Action) (err error) {
	o := orm.NewOrm()
	v := Action{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteAction deletes Action by Id and returns error if
// the record to be deleted doesn't exist
func DeleteAction(id string) (err error) {
	o := orm.NewOrm()
	v := Action{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Delete(&Action{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)
		}
	}
	return
}

//SoftDeleteAction 软删除活动
//Param id int64
//Param uname string
//return error
func SoftDeleteAction(id string, uname string) (err error) {
	o := orm.NewOrm()
	v := Action{Id: id}
	if err = o.Read(&v); err == nil {
		v.Isdelete = 1
		v.Updater = uname
		v.Utime = time.Now()
		_, err = o.Update(&v)
	}
	return
}

// 提醒
func NewMessage(f *Flowinstance, to *Stateinstance) {
	o := orm.NewOrm()
	var mes Message
	mes.BusyId = f.Id
	mes.Busy = f.Busyname
	mes.Title = "待办信息"
	mes.Isread = 0
	mes.Content = fmt.Sprintf("您有一个 %s 审批事务需要处理", f.Name)
	mes.Ctime = time.Now()
	mes.Utime = time.Now()
	mes.Creater = "admin"
	mes.Updater = "admin"
	mes.Id = libs.UUID()
	mes.User, _ = GetUserById(to.UserId)
	_, err := o.Insert(&mes)
	if err != nil {
		beego.Error(err)
	}

	var rec Message
	rec.BusyId = f.Id
	rec.Busy = f.Busyname
	rec.Title = "流程信息"
	rec.Isread = 0
	rec.Content = fmt.Sprintf("您的%s审批信息已变更", f.Name)
	rec.Ctime = time.Now()
	rec.Utime = time.Now()
	rec.Creater = "admin"
	rec.Updater = "admin"
	rec.Id = libs.UUID()
	rec.User, _ = GetUserById(f.UserId)
	_, err = o.Insert(&rec)
	if err != nil {
		beego.Error(err)
	}
}

func NewMessageWithTransaction(o orm.Ormer, f *Flowinstance, to *Stateinstance) error {
	var mes Message
	mes.BusyId = f.Id
	mes.Busy = f.Busyname
	mes.Title = "待办信息"
	mes.Isread = 0
	mes.Content = fmt.Sprintf("您有一个 %s 审批事务需要处理", f.Name)
	mes.Ctime = time.Now()
	mes.Utime = time.Now()
	mes.Creater = "admin"
	mes.Updater = "admin"
	mes.Id = libs.UUID()
	mes.User, _ = GetUserById(to.UserId)
	if to.UserId != "" {
		_, err := o.Insert(&mes)
		if err != nil {
			beego.Error(err)
			return err
		}
	}

	var rec Message
	rec.BusyId = f.Id
	rec.Busy = f.Busyname
	rec.Title = "流程信息"
	rec.Isread = 0
	rec.Content = fmt.Sprintf("您的%s审批信息已变更", f.Name)
	rec.Ctime = time.Now()
	rec.Utime = time.Now()
	rec.Creater = "admin"
	rec.Updater = "admin"
	rec.Id = libs.UUID()
	rec.User, _ = GetUserById(f.UserId)
	if f.UserId != "" {
		_, err := o.Insert(&rec)
		if err != nil {
			beego.Error(err)
			return err
		}
	}

	return nil
}

// DispatchAction 指派动作处理
// 0 生成stateins , tarnsIns
// 1 更新busytable 的指定字段
// 2 更具tutor_id 查询 user
// 3 修改 tostateIns 的 userId
func DispatchAction(o orm.Ormer, flow *Flowinstance,
	formStateInstance *Stateinstance, user *User, args map[string]interface{}) error {
	groupId := getRemarkFromArgs(args)
	toState := getToStateInstanceFromArgs(args)
	beego.Debug("DispatchAction=====================DispatchAction=================DispatchAction")
	//0 生成stateins , tarnsIns
	err := autoGenerateStateInstanceAndTransitionInstance(o, flow, formStateInstance, user, args)
	if err != nil {
		return err
	}
	// 1 更新busytable 的指定字段

	s, _ := GetStateById(toState.State.Id)
	//beego.Debug(s.Text)
	//beego.Debug(s.Key)
	//beego.Debug(flow.Busyname)
	//beego.Debug(flow.Busyid)
	//beego.Debug("groupid", groupId)
	params := orm.Params{s.Key: groupId}
	//beego.Debug("params", params)
	if _, err := o.QueryTable(flow.Busyname).Filter("Id", flow.Busyid).Update(params); err != nil {
		beego.Debug(err)
		//o.Rollback()
		return err
	}
	//str := `UPDATE %v SET "%v" = '%v' WHERE "id"= '%v'`
	//sql := fmt.Sprintf(str, flow.Busyname, s.Key, groupId, )
	// 更具tutor_id 查询 user
	leader, err := QueryLeaderUserByProfessorGroupId(o, groupId)
	if err != nil {
		beego.Debug(err)
		//o.Rollback()
		return err
	}
	//beego.Debug(leader)
	// 3 修改 tostateIns 的 userId
	//toStateRequery, err := GetStateinstanceById(toState.Id)
	//toStateRequery := &Stateinstance{Id: toState.Id}
	//if err = o.Read(toStateRequery); err != nil {
	//	beego.Debug(err)
	//	o.Rollback()
	//	return err
	//}
	//if _, err := o.LoadRelated(toStateRequery, "State"); err != nil {
	//	beego.Debug(err)
	//	o.Rollback()
	//	return err
	//}
	//if err != nil {
	//	beego.Debug(err)
	//	o.Rollback()
	//	return err
	//}
	//toStateRequery.UserId = leader.Id
	//_, err = o.Update(toState)
	//if err != nil {
	//	beego.Debug(err)
	//	o.Rollback()
	//	return err
	//}
	//beego.Debug(formStateInstance)
	if sum, err := o.QueryTable(new(Stateinstance)).Filter("Id", formStateInstance.Id).Update(orm.Params{
		"UserId": leader.Id,
	}); err != nil {
		beego.Debug(err)
		return err
	} else {
		beego.Debug(sum)
	}

	// 3 修改 transInsatence 的 userId
	//var transTo TransitionInstance
	if sum, err := o.QueryTable(new(TransitionInstance)).Filter("Isdelete", 0).Filter("From", formStateInstance.Id).Update(orm.Params{
		"UserId": leader.Id,
	}); err != nil {
		beego.Debug(err)
		return err
	} else {
		beego.Debug(sum)
	}
	//	One(&transTo);err != nil {
	//	beego.Debug(err)
	//	//o.Rollback()
	//	return err
	//}
	//transTo.UserId = leader.Id
	//_, err = o.Update(&transTo)
	//if err != nil {
	//	beego.Debug(err)
	//	//o.Rollback()
	//	return err
	//}
	return nil
}

// DispatchAction 选择动作处理
// 0 解析Remark未IdArray(User)
// 1 根据IdArray 生成分派StateInstance
// 2 根据生成的StateInstance 添加TransitionInstance
// 3 将添加TransitionInstance To字段只想原本的to
// 4 删除 临时 transitionInstance
func SelectAction(o orm.Ormer, flow *Flowinstance,
	formStateInstance *Stateinstance, user *User, args map[string]interface{}) error {
	//0 解析Remark未IdArray(User)
	//fromStateIns := getFromStateInstanceFromArgs(args)
	//toStateIns := getToStateInstanceFromArgs(args)
	toState := getToStateInstanceFromArgs(args)
	fromState := getFromStateInstanceFromArgs(args)
	idstr := getRemarkFromArgs(args)
	userIdArray := strings.Split(idstr, ",")
	if len(userIdArray) <= 0 {
		beego.Debug("remark 参数传递错误")
		return errors.New("remark 参数传递错误")
	}
	enable, err := GetEventByName("同意")
	if err != nil {
		beego.Debug(err)
		return err
	}
	disable, err := GetEventByName("不同意")
	if err != nil {
		beego.Debug(err)
		return err
	}
	mes, err := GetActionByName("提醒")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取分派事件
	fork, err := GetEventByName("分派")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取分派Action
	forkAction, err := GetActionByName("分派")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取汇聚事件
	join, err := GetEventByName("聚合")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取汇聚action
	joinAction, err := GetActionByName("聚合")
	if err != nil {
		beego.Debug(err)
		return err
	}
	insArray := make([]string, 0)
	state, err := GetStateById("1")
	if err != nil {
		beego.Debug(err)
		return err
	}
	tra, err := GetTransitionById("1")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取临时的trans
	trans := &TransitionInstance{}
	if err := o.QueryTable(new(TransitionInstance)).Filter("To", toState.Id).Filter("From", fromState.Id).One(trans); err != nil {
		beego.Debug(err)
		return err
	}
	beego.Debug("tansId", trans.Id)
	// 生成分派instance
	st := NewStateinstance()
	st.Flowinstance = flow
	st.State = state
	st.Text = "任务分派"
	st.Busyid = flow.Busyid
	st.Busyname = flow.Busyname
	st.Classname = "fork"
	if _, err := o.Insert(st); err != nil {
		beego.Debug(err)
		return err
	}
	args[TO] = st
	// 生成分派instance
	se := NewStateinstance()
	se.Flowinstance = flow
	se.State = state
	se.Text = "任务汇聚"
	se.Busyid = flow.Busyid
	se.Busyname = flow.Busyname
	se.Classname = "join"
	if _, err := o.Insert(se); err != nil {
		beego.Debug(err)
		return err
	}

	ti := NewTransitionInstance()
	ti.Flow = flow.Flow
	ti.Flowinstance = flow
	ti.Action = mes
	ti.EventId = enable.Id
	ti.Name = "同意"
	ti.Transition = tra
	ti.From = se.Id
	ti.To = trans.To
	if _, err := o.Insert(ti); err != nil {
		beego.Debug(err)
		return err
	}
	ts := NewTransitionInstance()
	ts.Flow = flow.Flow
	ts.Flowinstance = flow
	ts.Action = mes
	ts.EventId = disable.Id
	ts.Name = "不同意"
	ts.Transition = tra
	ts.From = se.Id
	ts.To = flow.Start
	if _, err := o.Insert(ts); err != nil {
		beego.Debug(err)
		return err
	}
	trans.To = st.Id
	trans.Status = 2
	if _, err := o.Update(st); err != nil {
		beego.Debug(err)
		return err
	}

	// 1 根据IdArray 生成分派StateInstance
	for _, v := range userIdArray {
		user := &User{Id: v}
		if err := o.Read(user); err != nil {
			beego.Debug(err)
			beego.Debug("无效的用户ID ")
			return err
		}
		s := newTaskInstance()
		insArray = append(insArray, s.Id)
		s.UserId = v
		s.Flowinstance = flow
		s.State = state
		s.Status = 1
		s.Busyid = formStateInstance.Busyid
		s.Busyname = formStateInstance.Busyname
		s.Text = "专家审核" + user.Abbr
		if _, err := o.Insert(s); err != nil {
			beego.Debug(err)
			return err
		}
	}

	// 2 根据生成的StateInstance 添加TransitionInstance
	var l []Stateinstance
	if _, err := o.QueryTable(new(Stateinstance)).Filter("Id__in", insArray).All(&l); err != nil {
		beego.Debug(err)
		return err
	}

	beego.Debug(l)
	// 同时生成分派和汇聚transitionInstance
	for _, val := range l {
		transitionS := &Transition{Id: libs.UUID(), Action: forkAction, EventId: fork.Id, Flow: flow.Flow, Ctime: time.Now(),
			Utime: time.Now(), Status: 1, Isdelete: 0, Creater: user.Abbr, Updater: user.Abbr}
		if _, err := o.Insert(transitionS); err != nil {
			beego.Debug(err)
			return err
		}
		// 分派
		ts := NewTransitionInstance()
		ts.Action = forkAction
		ts.Creater = user.Name
		ts.EventId = fork.Id
		ts.Flow = flow.Flow
		ts.Status = 2
		ts.Flowinstance = flow
		ts.From = st.Id
		ts.To = val.Id
		ts.Name = "分派"
		//ts.Transition = &t
		ts.Transition = transitionS
		ts.Updater = user.Name
		ts.Utime = ts.Ctime
		ts.UserId = val.UserId
		_, err := o.Insert(ts)
		if err != nil {
			beego.Error(err)
			//o.Rollback()
			return err
		}

		// 汇聚
		transitionE := &Transition{Id: libs.UUID(), Action: joinAction, EventId: join.Id, Flow: flow.Flow, Ctime: time.Now(),
			Utime: time.Now(), Status: 1, Isdelete: 0, Creater: user.Abbr, Updater: user.Abbr}
		if _, err := o.Insert(transitionE); err != nil {
			beego.Debug(err)
			return err
		}
		te := NewTransitionInstance()
		te.Action = joinAction
		te.Creater = user.Name
		te.EventId = join.Id
		te.Flow = flow.Flow
		te.Flowinstance = flow
		te.Status = 1
		//to, err := GetStateinstanceByFlowInsAndState(flow.Id, t.To)
		//if err != nil {
		//	beego.Error(err)
		//	o.Rollback()
		//	return  err
		//}
		te.Transition = transitionS
		te.From = val.Id
		te.To = se.Id
		//fstr := strtool.GetBetweenStr(t.Fromid, "$")
		//ts.Fromid = ts.From + fstr
		//tstr := strtool.GetBetweenStr(t.Toid, "$")
		//ts.Toid = ts.To + tstr
		te.Name = "聚合"
		//ts.Transition = &t
		te.Updater = user.Name
		te.Utime = ts.Ctime
		te.UserId = val.UserId
		_, err = o.Insert(te)
		if err != nil {
			beego.Error(err)
			//o.Rollback()
			return err
		}
	}
	// 删除临时 transitionInstance
	//if sum, err := o.Delete(trans); err != nil || sum != 1 {
	//	beego.Debug(err)
	//	beego.Debug(sum)
	//	return err
	//}
	return nil
}

// SelectActionHandler SELECT 事件处理
// 0 解析remark 为UserIdArray
// 1 构造fork与join instance
// 2 修改trans，to， from，添加指向from为join， 的trans
// 3 构造task 与 transition instance by UserIdArray
// 4 修改flowInstance.Currentstate为fork
func SelectActionHandler(o orm.Ormer, args map[string]interface{}) error {
	// 0 解析remark 为UserIdArray , 与其它必要参数
	fromStateIns := getFromStateInstanceFromArgs(args)
	toStateIns := getToStateInstanceFromArgs(args)
	flowIns := getFlowinstanceFromArgs(args)
	arrayStr := getRemarkFromArgs(args)
	userIdArray := strings.Split(arrayStr, ",")
	if len(userIdArray) <= 0 {
		beego.Debug("err id strings")
		return errors.New("err id strings")
	}
	// 1 构造fork与join instance
	fork := newForkInstance()
	fork.State, fork.Flowinstance, fork.Busyname, fork.Busyid = fromStateIns.State, flowIns, flowIns.Busyname, flowIns.Busyid
	if _, err := o.Insert(fork); err != nil {
		beego.Debug(err)
		return err
	}

	join := newJoinInstance()
	join.State, join.Flowinstance, join.Busyname, join.Busyid = toStateIns.State, flowIns, flowIns.Busyname, flowIns.Busyid
	if _, err := o.Insert(join); err != nil {
		beego.Debug(err)
		return err
	}

	// 修改 已存在的trans， from 不变，to 指向fork，添加一个trans， from只想join， to指向 toState
	enableEvent, err := GetEventByName("同意")
	if err != nil {
		beego.Debug(err)
		return err
	}
	disableEvent, err := GetEventByName("不同意")
	if err != nil {
		beego.Debug(err)
		return err
	}
	mesAction, err := GetActionByName("提醒")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取分派事件
	forkEvent, err := GetEventByName("分派")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取分派Action
	forkAction, err := GetActionByName("分派")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取汇聚事件
	joinEvent, err := GetEventByName("聚合")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取汇聚action
	joinAction, err := GetActionByName("聚合")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取上报Event
	approveEvent, err := GetEventByName("上报")
	if err != nil {
		beego.Debug(err)
		return err
	}
	forkTrans := &TransitionInstance{From: fromStateIns.Id, To: toStateIns.Id}
	if err := o.Read(forkTrans, "From", "To"); err != nil {
		beego.Debug(err)
		return err
	}
	forkTrans.To, forkTrans.Action, forkTrans.EventId, forkTrans.Name, forkTrans.Status = fork.Id, mesAction, approveEvent.Id, "指派", 2
	fork.Ctime, fork.Utime = time.Now(), time.Now()
	if _, err := o.Update(forkTrans); err != nil {
		beego.Debug(err)
		return err
	}
	joinTrans1 := NewTransitionInstance()
	joinTrans1.Flowinstance, joinTrans1.Flow, joinTrans1.EventId, joinTrans1.Action = flowIns, flowIns.Flow, enableEvent.Id, mesAction
	joinTrans1.From, joinTrans1.To, joinTrans1.Transition, joinTrans1.Name = join.Id, toStateIns.Id, forkTrans.Transition, enableEvent.Name
	if _, err := o.Insert(joinTrans1); err != nil {
		beego.Debug(err)
		return err
	}

	joinTrans2 := NewTransitionInstance()
	joinTrans2.Flowinstance, joinTrans2.Flow, joinTrans2.EventId, joinTrans2.Action = flowIns, flowIns.Flow, disableEvent.Id, mesAction
	joinTrans2.From, joinTrans2.To, joinTrans2.Transition, joinTrans2.Name = join.Id, flowIns.Start, forkTrans.Transition, disableEvent.Name
	if _, err := o.Insert(joinTrans2); err != nil {
		beego.Debug(err)
		return err
	}

	// 3 构造task 与 transition instance by UserIdArray
	for _, v := range userIdArray {
		//beego.Debug(v)
		user, err := GetUserById(v)
		if err != nil {
			beego.Debug(err)
			return err
		}
		// insert task
		ins := newTaskInstance()
		ins.State = fromStateIns.State
		ins.Flowinstance, ins.Busyname, ins.Busyid, ins.Text, ins.UserId = flowIns, flowIns.Busyname, flowIns.Busyid, user.Abbr+"审核", v
		// TODO 在此添加特殊标记，用于显示评分选项,
		ins.Remark = "ZHUANJIASHENHE"
		ins.Opinions = "CALCULATE_FLAG"
		if _, err := o.Insert(ins); err != nil {
			beego.Debug(err)
			return err
		}

		// insert connection
		before := NewTransitionInstance()
		before.Flowinstance, before.Flow, before.Transition = flowIns, flowIns.Flow, forkTrans.Transition
		before.Name, before.Action, before.EventId = forkEvent.Name, forkAction, forkEvent.Id
		before.From, before.To = fork.Id, ins.Id
		if _, err := o.Insert(before); err != nil {
			beego.Debug(err)
			return err
		}

		after := NewTransitionInstance()
		after.Flowinstance, after.Flow, after.Transition = flowIns, flowIns.Flow, forkTrans.Transition
		after.Name, after.Action, after.EventId = joinEvent.Name, joinAction, joinEvent.Id
		after.From, after.To, after.UserId = ins.Id, join.Id, v
		if _, err := o.Insert(after); err != nil {
			beego.Debug(err)
			return err
		}
	}

	// 4 修改flowInstance.Currentstate为fork
	flow := &Flowinstance{Id: flowIns.Id}
	if err := o.Read(flow); err != nil {
		beego.Debug(err)
		return err
	}
	flow.Currentstate = fork.Id
	join.Ctime, join.Utime = time.Now(), time.Now()
	toStateIns.Ctime, toStateIns.Utime = time.Now(), time.Now()

	if _, err := o.Update(join); err != nil {
		beego.Debug(err)
		return err
	}
	if _, err := o.Update(toStateIns); err != nil {
		beego.Debug(err)
		return err
	}
	if _, err := o.Update(flow); err != nil {
		beego.Debug(err)
		return err
	}
	args[TO] = fork
	args[ACTOIN] = mesAction.Id
	args[FLOWINSTANCE] = flow
	return nil
}

// SelectActionHandler SELECT 事件处理
// 0 解析remark 为UserIdArray
// 1 构造fork与join instance
// 2 修改trans，to， from，添加指向from为join， 的trans
// 3 构造task 与 transition instance by UserIdArray
// 4 修改flowInstance.Currentstate为fork
func GroupActionHandler(o orm.Ormer, args map[string]interface{}) error {
	// 0 解析remark 为UserIdArray , 与其它必要参数
	fromStateIns := getFromStateInstanceFromArgs(args)
	toStateIns := getToStateInstanceFromArgs(args)
	flowIns := getFlowinstanceFromArgs(args)
	//arrayStr := getRemarkFromArgs(args)
	groupId := getRemarkFromArgs(args)

	userIdArray, err := QueryUserByImsProfessorGroup(groupId)
	if err != nil || len(userIdArray) <= 0 {
		beego.Debug("err id strings")
		return errors.New("err id strings")
	}
	// 1 构造fork与join instance
	fork := newForkInstance()
	fork.State, fork.Flowinstance, fork.Busyname, fork.Busyid = fromStateIns.State, flowIns, flowIns.Busyname, flowIns.Busyid
	if _, err := o.Insert(fork); err != nil {
		beego.Debug(err)
		return err
	}

	join := newJoinInstance()
	join.State, join.Flowinstance, join.Busyname, join.Busyid = toStateIns.State, flowIns, flowIns.Busyname, flowIns.Busyid
	if _, err := o.Insert(join); err != nil {
		beego.Debug(err)
		return err
	}

	// 修改 已存在的trans， from 不变，to 指向fork，添加一个trans， from只想join， to指向 toState
	enableEvent, err := GetEventByName("同意")
	if err != nil {
		beego.Debug(err)
		return err
	}
	disableEvent, err := GetEventByName("不同意")
	if err != nil {
		beego.Debug(err)
		return err
	}
	//sumbitEvent, err := GetEventByName("评分")
	//if err != nil {
	//	beego.Debug(err)
	//	return err
	//}
	mesAction, err := GetActionByName("提醒")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取分派事件
	forkEvent, err := GetEventByName("分派")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取分派Action
	forkAction, err := GetActionByName("分派")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取汇聚事件
	joinEvent, err := GetEventByName("聚合")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取汇聚action
	joinAction, err := GetActionByName("聚合")
	if err != nil {
		beego.Debug(err)
		return err
	}
	// 获取上报Event
	approveEvent, err := GetEventByName("上报")
	if err != nil {
		beego.Debug(err)
		return err
	}
	forkTrans := &TransitionInstance{From: fromStateIns.Id, To: toStateIns.Id}
	if err := o.Read(forkTrans, "From", "To"); err != nil {
		beego.Debug(err)
		return err
	}
	forkTrans.To, forkTrans.Action, forkTrans.EventId, forkTrans.Name, forkTrans.Status = fork.Id, mesAction, approveEvent.Id, "指派", 2
	fork.Ctime, fork.Utime = time.Now(), time.Now()
	if _, err := o.Update(forkTrans); err != nil {
		beego.Debug(err)
		return err
	}
	joinTrans1 := NewTransitionInstance()
	joinTrans1.Flowinstance, joinTrans1.Flow, joinTrans1.EventId, joinTrans1.Action = flowIns, flowIns.Flow, enableEvent.Id, mesAction
	joinTrans1.From, joinTrans1.To, joinTrans1.Transition, joinTrans1.Name = join.Id, toStateIns.Id, forkTrans.Transition, enableEvent.Name
	if _, err := o.Insert(joinTrans1); err != nil {
		beego.Debug(err)
		return err
	}

	joinTrans2 := NewTransitionInstance()
	joinTrans2.Flowinstance, joinTrans2.Flow, joinTrans2.EventId, joinTrans2.Action = flowIns, flowIns.Flow, disableEvent.Id, mesAction
	joinTrans2.From, joinTrans2.To, joinTrans2.Transition, joinTrans2.Name = join.Id, flowIns.Start, forkTrans.Transition, disableEvent.Name
	if _, err := o.Insert(joinTrans2); err != nil {
		beego.Debug(err)
		return err
	}

	// 3 构造task 与 transition instance by UserIdArray
	for _, v := range userIdArray {
		//beego.Debug(v)
		//user, err := GetUserById(v)
		//if err != nil {
		//	beego.Debug(err)
		//	return err
		//}
		// insert task
		ins := newTaskInstance()
		ins.State = fromStateIns.State
		ins.Flowinstance, ins.Busyname, ins.Busyid, ins.Text, ins.UserId = flowIns, flowIns.Busyname, flowIns.Busyid, v.Abbr+"审核", v.Id
		// TODO 在此添加特殊标记，用于显示评分选项,
		ins.Remark = "ZHUANJIASHENHE"
		ins.Opinions = "CALCULATE_FLAG"
		if _, err := o.Insert(ins); err != nil {
			beego.Debug(err)
			return err
		}

		// insert connection
		before := NewTransitionInstance()
		before.Flowinstance, before.Flow, before.Transition = flowIns, flowIns.Flow, forkTrans.Transition
		before.Name, before.Action, before.EventId = forkEvent.Name, forkAction, forkEvent.Id
		before.From, before.To = fork.Id, ins.Id
		if _, err := o.Insert(before); err != nil {
			beego.Debug(err)
			return err
		}

		after := NewTransitionInstance()
		after.Flowinstance, after.Flow, after.Transition = flowIns, flowIns.Flow, forkTrans.Transition
		after.Name, after.Action, after.EventId = joinEvent.Name, joinAction, joinEvent.Id
		after.From, after.To, after.UserId = ins.Id, join.Id, v.Id
		if _, err := o.Insert(after); err != nil {
			beego.Debug(err)
			return err
		}
	}

	// 4 修改flowInstance.Currentstate为fork
	flow := &Flowinstance{Id: flowIns.Id}
	if err := o.Read(flow); err != nil {
		beego.Debug(err)
		return err
	}
	flow.Currentstate = fork.Id
	join.Ctime, join.Utime = time.Now(), time.Now()
	toStateIns.Ctime, toStateIns.Utime = time.Now(), time.Now()

	if _, err := o.Update(join); err != nil {
		beego.Debug(err)
		return err
	}
	if _, err := o.Update(toStateIns); err != nil {
		beego.Debug(err)
		return err
	}
	if _, err := o.Update(flow); err != nil {
		beego.Debug(err)
		return err
	}
	args[TO] = fork
	args[ACTOIN] = mesAction.Id
	args[FLOWINSTANCE] = flow
	return nil
}

type Score struct {
	Total   float64 `json: "total"`
	First   float64 `json: "first"`
	Second  float64 `json: "second"`
	Third   float64 `json: "third"`
	Forth   float64 `json: "forth"`
	Fifth   float64 `json: "fifth"`
	Sixth   float64 `json: "sixth"`
	Seventh float64 `json: "seventh"`
	Eighth  float64 `json: "eighth"`
}

//{"total":46,"first":11,"second":11,"third":11,"forth":11,"fifth":1,"sixth":1}

func ColculateAction(o orm.Ormer, flow *Flowinstance,
	formStateInstance *Stateinstance, user *User, args map[string]interface{}) error {
	tans, err := GetStateInsByFlowAndFlag(flow.Id, "CALCULATE_FLAG")
	if err != nil {
		beego.Debug(err)
		return err
	}
	beego.Debug(tans)
	s := make([]*Score, 0)
	for k, _ := range tans {
		node := &Score{}
		beego.Debug(tans[k].Remark)
		err = json.Unmarshal([]byte(tans[k].Remark), node)
		beego.Debug(err)
		s = append(s, node)
	}
	total := 0.0
	for _, v := range s {
		beego.Debug(v)
		total += v.Total
	}
	avg := total / float64(len(s))
	m := &ImsProject{}
	switch flow.Busyname {
	case "ims_project":
		m, _ = GetImsProjectById(flow.Busyid)
		m.Score1 = int(avg)
	case "ims_project_medium_term":
		m, _ = GetImsProjectByMediumTermId(flow.Busyid)
		m.Score2 = int(avg)
	case "ims_project_finish_report":
		m, _ = GetImsProjectByFinishReportId(flow.Busyid)
		m.Score3 = int(avg)
	}

	_, err = o.Update(m)

	return err
}
